using System;
using System.Text;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using Microsoft.CSharp;
using System.Collections;
using System.Linq.Expressions;
using Microsoft.VisualStudio.DebuggerVisualizers;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Collections.ObjectModel;
using System.Linq;

static class ExpressionTreeExtention
{
    static string ExtractName(string name)
    {
        int i = name.LastIndexOf("`");
        if (i > 0)
            name = name.Substring(0, i);
        return name;
    }

    static string ExtractGenericArguments(Type[] names)
    {
        StringBuilder builder = new StringBuilder("<");
        foreach (Type genericArgument in names)
        {
            if (builder.Length != 1) builder.Append(", ");
            builder.Append(ObtainOriginalName(genericArgument));
        }
        builder.Append(">");
        return builder.ToString();
    }

    public static string ObtainOriginalName(this Type type)
    {
        if (!type.IsGenericType)
        {
            return type.Name;
        }
        else
        {
            return ExtractName(type.Name) + ExtractGenericArguments(type.GetGenericArguments());
        }
    }

    public static string ObtainOriginalMethodName(this MethodInfo method)
    {
        if (!method.IsGenericMethod)
        {
            return method.Name;
        }
        else
        {
            return ExtractName(method.Name) + ExtractGenericArguments(method.GetGenericArguments());
        }
    }
}

[Serializable]
public class ExpressionTreeNode : TreeNode
{
    public ExpressionTreeNode(SerializationInfo info, StreamingContext context) : base(info, context) { }

    protected override void Serialize(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext context)
    {
        base.Serialize(si, context);
    }

    public ExpressionTreeNode(Object value)
    {
        Type type = value.GetType();
        Text = type.ObtainOriginalName();
       
        if (value is Expression)
        {
            ImageIndex = 2;
            SelectedImageIndex = 2;

            PropertyInfo[] propertyInfos = null;
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Expression<>))
            {
                propertyInfos = type.BaseType.GetProperties(BindingFlags.Public |  BindingFlags.Instance);
            }
            else
            {
                propertyInfos = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            }

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if ((propertyInfo.Name != "nodeType"))
                {
                    Nodes.Add(new AttributeNode(value, propertyInfo));
                }
            }
        }
        else
        {
            ImageIndex = 4;
            SelectedImageIndex = 4;
            Text = "\"" + value.ToString() + "\"";
        }
    }
}

[Serializable]
public class AttributeNode : TreeNode
{
    public AttributeNode(SerializationInfo info, StreamingContext context) : base(info, context) { }
    public AttributeNode(Object attribute, PropertyInfo propertyInfo)
    {
        Text = propertyInfo.Name + " : " + propertyInfo.PropertyType.ObtainOriginalName();
        ImageIndex = 3;
        SelectedImageIndex = 3;

        Object value = propertyInfo.GetValue(attribute,null);
        if (value != null)
        {
            if (value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(ReadOnlyCollection<>))
            {
                if ((int)value.GetType().InvokeMember("get_Count", BindingFlags.InvokeMethod, null, value, null) == 0)
                {
                    Text += " : Empty";
                }
                else
                {
                    foreach (object tree in (IEnumerable)value)
                    {
                        if (tree is Expression)
                        {
                            Nodes.Add(new ExpressionTreeNode(tree));
                        }
                        else if (tree is MemberAssignment)
                        {
                            Nodes.Add(new ExpressionTreeNode(((MemberAssignment)tree).Expression));
                        }
                    }
                }
            }
            else if (value is Expression)
            {
                Text += ((Expression)value).NodeType;
                Nodes.Add(new ExpressionTreeNode(value));
            }
            else if (value is MethodInfo)
            {
                MethodInfo minfo = value as MethodInfo;
                Text += " : \"" + minfo.ObtainOriginalMethodName() + "\"";
            }
            else if (value is Type)
            {
                Type minfo = value as Type;
                Text += " : \"" + minfo.ObtainOriginalName() + "\"";
            }
            else
            {
                Text += " : \"" + value.ToString() + "\"";
            }
        }
        else
        {
            Text += " : null";
        }
    }
    protected override void Serialize(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext context)
    {
        base.Serialize(si, context);
    }

}
